// Copyright 2011 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "google/protobuf-expectation/proto-kit-generator.h"

#include <string>

#include "google/protobuf-expectation/proto-kit-generator_test.pb.h"
#include "google/protobuf/descriptor.pb.h"
#include "google/protobuf/descriptor.h"
#include "gtest/gtest.h"

using std::string;

using google::protobuf::DescriptorProto;
using google::protobuf::FieldDescriptorProto;
using google::protobuf::FileDescriptorProto;

namespace google {
namespace protobuf_expectation {

class ProtoKitGeneratorTest : public ::testing::Test {
 protected:
  const DescriptorProto* GetDescriptorProto(const string& name) {
    for (int i = 0; i < file_descriptor_.message_type_size(); ++i) {
      if (file_descriptor_.message_type(i).name() == name) {
        return &file_descriptor_.message_type(i);
      }
    }
    return NULL;
  }

  void ExpectAtIndexField(
      const FieldDescriptorProto& field_descriptor) {
    // optional ValueKit at_index = # (the tag number is not important here)
    EXPECT_EQ("at_index", field_descriptor.name());
    EXPECT_TRUE(field_descriptor.has_number());
    EXPECT_EQ(FieldDescriptorProto::LABEL_OPTIONAL,
              field_descriptor.label());
    EXPECT_EQ(FieldDescriptorProto::TYPE_MESSAGE,
              field_descriptor.type());
    EXPECT_EQ(".google.protobuf_expectation.ValueKit",
              field_descriptor.type_name());
  }

  // Test if a descriptor has four fields of a proto kit to describe
  // expectatsions of a repeated message field.
  void ExpectRepeatedMessageKit(
      const DescriptorProto& repeated_proto_kit,
      const string& proto_kit_name) {
    EXPECT_EQ(4, repeated_proto_kit.field_size());
    // optional ValueKit field_size = # (the tag number is not important here)
    EXPECT_EQ("field_size", repeated_proto_kit.field(0).name());
    EXPECT_TRUE(repeated_proto_kit.field(0).has_number());
    EXPECT_EQ(FieldDescriptorProto::LABEL_OPTIONAL,
              repeated_proto_kit.field(0).label());
    EXPECT_EQ(FieldDescriptorProto::TYPE_MESSAGE,
              repeated_proto_kit.field(0).type());
    EXPECT_EQ(".google.protobuf_expectation.ValueKit",
              repeated_proto_kit.field(0).type_name());
    // optional ProtoKit for_each = #
    EXPECT_EQ("for_each", repeated_proto_kit.field(1).name());
    EXPECT_TRUE(repeated_proto_kit.field(1).has_number());
    EXPECT_EQ(FieldDescriptorProto::LABEL_OPTIONAL,
              repeated_proto_kit.field(1).label());
    EXPECT_EQ(FieldDescriptorProto::TYPE_MESSAGE,
              repeated_proto_kit.field(1).type());
    EXPECT_EQ(proto_kit_name, repeated_proto_kit.field(1).type_name());
    // repeated ProtoKit have = #
    EXPECT_EQ("have", repeated_proto_kit.field(2).name());
    EXPECT_TRUE(repeated_proto_kit.field(2).has_number());
    EXPECT_EQ(FieldDescriptorProto::LABEL_REPEATED,
              repeated_proto_kit.field(2).label());
    EXPECT_EQ(FieldDescriptorProto::TYPE_MESSAGE,
              repeated_proto_kit.field(2).type());
    EXPECT_EQ(proto_kit_name, repeated_proto_kit.field(2).type_name());
    // repeated ProtoKit do_not_have = #
    EXPECT_EQ("do_not_have", repeated_proto_kit.field(3).name());
    EXPECT_TRUE(repeated_proto_kit.field(3).has_number());
    EXPECT_EQ(FieldDescriptorProto::LABEL_REPEATED,
              repeated_proto_kit.field(3).label());
    EXPECT_EQ(FieldDescriptorProto::TYPE_MESSAGE,
              repeated_proto_kit.field(3).type());
    EXPECT_EQ(proto_kit_name, repeated_proto_kit.field(3).type_name());
  }

  ProtoKitGenerator generator_;
  FileDescriptorProto file_descriptor_;
  string error_;
};

TEST_F(ProtoKitGeneratorTest, FileDescriptor) {
  // The input FileDescriptor is obtained through SingularInt32's descriptor.
  EXPECT_TRUE(generator_.GenerateDescriptorProto(
      google::protobuf_expectation::SingularInt32::descriptor()->file(),
      &file_descriptor_, &error_));

  EXPECT_EQ("google.protobuf_expectation", file_descriptor_.package());
  EXPECT_EQ(1, file_descriptor_.dependency_size());
EXPECT_EQ("google/protobuf-expectation/proto-kit.proto",
            file_descriptor_.dependency(0));
  EXPECT_LT(0, file_descriptor_.message_type_size());
  EXPECT_EQ(0, file_descriptor_.enum_type_size());
  EXPECT_EQ(0, file_descriptor_.service_size());
  EXPECT_EQ(0, file_descriptor_.extension_size());
}

TEST_F(ProtoKitGeneratorTest, SingularInt32) {
  EXPECT_TRUE(generator_.GenerateDescriptorProto(
      google::protobuf_expectation::SingularInt32::descriptor()->file(),
      &file_descriptor_, &error_));

  // A message to describe expectations of SingularInt32 message is generated.
  const DescriptorProto* proto_kit = GetDescriptorProto("SingularInt32Kit");
  ASSERT_TRUE(proto_kit != NULL);
  EXPECT_EQ("SingularInt32Kit", proto_kit->name());
  EXPECT_EQ(2, proto_kit->field_size());
  // optional ValueKit int32_field = 1
  EXPECT_EQ("int32_field", proto_kit->field(0).name());
  EXPECT_EQ(1, proto_kit->field(0).number());
  EXPECT_EQ(FieldDescriptorProto::LABEL_OPTIONAL,
            proto_kit->field(0).label());
  EXPECT_EQ(FieldDescriptorProto::TYPE_MESSAGE,
            proto_kit->field(0).type());
  EXPECT_EQ(".google.protobuf_expectation.ValueKit",
            proto_kit->field(0).type_name());
  // optional ValueKit at_index = #
  ExpectAtIndexField(proto_kit->field(1));

  // Another message to describe expectations of repeated SingularInt32 is
  // generated.
  const DescriptorProto* repeated_proto_kit =
      GetDescriptorProto("RepeatedSingularInt32Kit");
  ASSERT_TRUE(repeated_proto_kit != NULL);
  EXPECT_EQ("RepeatedSingularInt32Kit", repeated_proto_kit->name());
  ExpectRepeatedMessageKit(*repeated_proto_kit, "SingularInt32Kit");
}

TEST_F(ProtoKitGeneratorTest, RepeatedInt32) {
  EXPECT_TRUE(generator_.GenerateDescriptorProto(
      google::protobuf_expectation::RepeatedInt32::descriptor()->file(),
      &file_descriptor_, &error_));

  // A message to describe expectations of RepeatedInt32 message is generated.
  const DescriptorProto* proto_kit = GetDescriptorProto("RepeatedInt32Kit");
  ASSERT_TRUE(proto_kit != NULL);
  EXPECT_EQ("RepeatedInt32Kit", proto_kit->name());
  EXPECT_EQ(2, proto_kit->field_size());
  // optional RepeatedValueKit int32_field = 2
  EXPECT_EQ("int32_field", proto_kit->field(0).name());
  EXPECT_EQ(2, proto_kit->field(0).number());
  EXPECT_EQ(FieldDescriptorProto::LABEL_OPTIONAL,
            proto_kit->field(0).label());
  EXPECT_EQ(FieldDescriptorProto::TYPE_MESSAGE,
            proto_kit->field(0).type());
  EXPECT_EQ(".google.protobuf_expectation.RepeatedValueKit",
            proto_kit->field(0).type_name());
  // optional ValueKit at_index = #
  ExpectAtIndexField(proto_kit->field(1));

  // Another message to describe expectations of repeated RepeatedInt32 is
  // generated.
  const DescriptorProto* repeated_proto_kit =
      GetDescriptorProto("RepeatedRepeatedInt32Kit");
  ASSERT_TRUE(repeated_proto_kit != NULL);
  EXPECT_EQ("RepeatedRepeatedInt32Kit", repeated_proto_kit->name());
  ExpectRepeatedMessageKit(*repeated_proto_kit, "RepeatedInt32Kit");
}

TEST_F(ProtoKitGeneratorTest, SingularMessage) {
  EXPECT_TRUE(generator_.GenerateDescriptorProto(
      google::protobuf_expectation::SingularMessage::descriptor()->file(),
      &file_descriptor_, &error_));

  // A message to describe expectations of SingularMessage message is generated.
  const DescriptorProto* proto_kit = GetDescriptorProto("SingularMessageKit");
  ASSERT_TRUE(proto_kit != NULL);
  EXPECT_EQ("SingularMessageKit", proto_kit->name());
  EXPECT_EQ(2, proto_kit->field_size());
  // optional SingularInt32Kit message_field = 3
  EXPECT_EQ("message_field", proto_kit->field(0).name());
  EXPECT_EQ(3, proto_kit->field(0).number());
  EXPECT_EQ(FieldDescriptorProto::LABEL_OPTIONAL,
            proto_kit->field(0).label());
  EXPECT_EQ(FieldDescriptorProto::TYPE_MESSAGE,
            proto_kit->field(0).type());
  EXPECT_EQ(".google.protobuf_expectation.SingularInt32Kit",
            proto_kit->field(0).type_name());
  // optional ValueKit at_index = #
  ExpectAtIndexField(proto_kit->field(1));

  // Another message to describe expectations of repeated SingularMessage is
  // generated.
  const DescriptorProto* repeated_proto_kit =
      GetDescriptorProto("RepeatedSingularMessageKit");
  ASSERT_TRUE(repeated_proto_kit != NULL);
  EXPECT_EQ("RepeatedSingularMessageKit", repeated_proto_kit->name());
  ExpectRepeatedMessageKit(*repeated_proto_kit, "SingularMessageKit");
}

TEST_F(ProtoKitGeneratorTest, RepeatedMessage) {
  EXPECT_TRUE(generator_.GenerateDescriptorProto(
      google::protobuf_expectation::RepeatedMessage::descriptor()->file(),
      &file_descriptor_, &error_));

  // A message to describe expectations of RepeatedMessage message is generated.
  const DescriptorProto* proto_kit = GetDescriptorProto("RepeatedMessageKit");
  ASSERT_TRUE(proto_kit != NULL);
  EXPECT_EQ("RepeatedMessageKit", proto_kit->name());
  EXPECT_EQ(2, proto_kit->field_size());
  // optional RepeatedSingularInt32Kit message_field = 4
  EXPECT_EQ("message_field", proto_kit->field(0).name());
  EXPECT_EQ(4, proto_kit->field(0).number());
  EXPECT_EQ(FieldDescriptorProto::LABEL_OPTIONAL,
            proto_kit->field(0).label());
  EXPECT_EQ(FieldDescriptorProto::TYPE_MESSAGE,
            proto_kit->field(0).type());
  EXPECT_EQ(".google.protobuf_expectation.RepeatedSingularInt32Kit",
            proto_kit->field(0).type_name());
  // optional ValueKit at_index = #
  ExpectAtIndexField(proto_kit->field(1));

  // Another message to describe expectations of repeated RepeatedMessage is
  // generated.
  const DescriptorProto* repeated_proto_kit =
      GetDescriptorProto("RepeatedRepeatedMessageKit");
  ASSERT_TRUE(repeated_proto_kit != NULL);
  EXPECT_EQ("RepeatedRepeatedMessageKit", repeated_proto_kit->name());
  ExpectRepeatedMessageKit(*repeated_proto_kit, "RepeatedMessageKit");
}

TEST_F(ProtoKitGeneratorTest, NestedMessage) {
  EXPECT_TRUE(generator_.GenerateDescriptorProto(
      google::protobuf_expectation::NestedMessage::descriptor()->file(),
      &file_descriptor_, &error_));

  // A message to describe expectations of NestedMessage message is generated.
  const DescriptorProto* proto_kit = GetDescriptorProto("NestedMessageKit");
  ASSERT_TRUE(proto_kit != NULL);
  EXPECT_EQ("NestedMessageKit", proto_kit->name());
  EXPECT_EQ(2, proto_kit->field_size());
  // optional SingularStringKit message_field = 6
  EXPECT_EQ("message_field", proto_kit->field(0).name());
  EXPECT_EQ(6, proto_kit->field(0).number());
  EXPECT_EQ(FieldDescriptorProto::LABEL_OPTIONAL,
            proto_kit->field(0).label());
  EXPECT_EQ(FieldDescriptorProto::TYPE_MESSAGE,
            proto_kit->field(0).type());
  EXPECT_EQ(".google.protobuf_expectation.NestedMessageKit.SingularStringKit",
            proto_kit->field(0).type_name());
  // optional ValueKit at_index = #
  ExpectAtIndexField(proto_kit->field(1));
  EXPECT_EQ(2, proto_kit->nested_type_size());
  // A message to describe expectations of SingularString message is generated
  // as a nested type inside NestedMessageKit.
  const DescriptorProto& nested_proto_kit = proto_kit->nested_type(0);
  EXPECT_EQ("SingularStringKit", nested_proto_kit.name());
  EXPECT_EQ(2, nested_proto_kit.field_size());
  // optional ValueKit string_field = 5
  EXPECT_EQ("string_field", nested_proto_kit.field(0).name());
  EXPECT_EQ(5, nested_proto_kit.field(0).number());
  EXPECT_EQ(FieldDescriptorProto::LABEL_OPTIONAL,
            nested_proto_kit.field(0).label());
  EXPECT_EQ(FieldDescriptorProto::TYPE_MESSAGE,
            nested_proto_kit.field(0).type());
  EXPECT_EQ(".google.protobuf_expectation.ValueKit",
            nested_proto_kit.field(0).type_name());
  // optional ValueKit at_index = #
  ExpectAtIndexField(proto_kit->field(1));
  // Another message to describe expectations of repeated SingularMessageKit is
  // generated.
  const DescriptorProto& nested_repeated_proto_kit = proto_kit->nested_type(1);
  EXPECT_EQ("RepeatedSingularStringKit", nested_repeated_proto_kit.name());
  ExpectRepeatedMessageKit(nested_repeated_proto_kit, "SingularStringKit");

  // Another message to describe expectations of repeated SingularMessageKit is
  // generated.
  const DescriptorProto* repeated_proto_kit =
      GetDescriptorProto("RepeatedNestedMessageKit");
  ASSERT_TRUE(repeated_proto_kit != NULL);
  EXPECT_EQ("RepeatedNestedMessageKit", repeated_proto_kit->name());
  ExpectRepeatedMessageKit(*repeated_proto_kit, "NestedMessageKit");
}

}  // namespace protobuf_expectation
}  // namespace google
